﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Xml.Linq;

namespace Duellum.Core
{
	[ImmutableObject(true)] //Aspect: all IAugValues should be immutable
	public interface IAugValue
	{
		object GetValue(AugObject owner);
		
		//TODO: consider the following:
		//object GetLocalValue(AugObject owner); //without functionAugValues
		//IAugValue CombineValue(AugObject owner, IAugValue augValue);
	}
	
	internal interface IXSerializable
	{
		XObject ToXml(XName name);
	}
	
	public static class AugValueExt
	{
		static public T GetValue<T>(this IAugValue value, AugObject owner)
		{
			return (T)value.GetValue(owner);
		}
		
		static public IAugValue Create(object value, AugProperty prop)
		{
			if (value is LambdaExpression)	return FunctionAugValue.Create((LambdaExpression)value, prop);
			if (value is Delegate)			return FunctionAugValue.Create((Delegate)value, prop);
			return new ConstantAugValue(value);
		}
		
		static public XObject ToXml(this KeyValuePair<AugProperty,IAugValue> pair)
		{
			if (pair.Value is IXSerializable) return ((IXSerializable)pair.Value).ToXml(pair.Key.Name);
			return new XAttribute(pair.Key.Name, pair.Value.ToString());
		}
	}
	
	[ImmutableObject(true)]
	internal sealed class ConstantAugValue : IAugValue, IXSerializable
	{
		public object Value { get; private set; }
		public object GetValue(AugObject owner) { return Value; }
		
		public ConstantAugValue(object value) { Value = value; }
		
		static public IAugValue Create(object value)
		{
			return new ConstantAugValue(value);
		}

		public override string ToString()
		{
			return ToString(false);
		}

		public string ToString(bool withQuote)
		{
			var value = (Value == null) ? "null" : Value.ToString();
			return (withQuote) ? string.Concat("'", value, "'") : value;
		}
		
		public XObject ToXml(XName name)
		{
			return new XAttribute(name, this.ToString(false));
		}
	}
}
